package com.ggb.reactive.service

import com.ggb.reactive.constant.ACTION_SUCCESS
import com.ggb.reactive.domain.dto.DishDTO
import com.ggb.reactive.domain.dto.DishPageQueryDTO
import com.ggb.reactive.domain.entity.Dish
import com.ggb.reactive.model.PageResult
import com.ggb.reactive.model.Result
import lombok.RequiredArgsConstructor
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.PageRequest
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.relational.core.query.Criteria
import org.springframework.data.relational.core.query.Query
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.stereotype.Service
import reactor.core.publisher.Mono
import java.time.LocalDateTime

@Service
@RequiredArgsConstructor
class DishService(
    private val r2dbcEntityTemplate: R2dbcEntityTemplate,
    private val databaseClient: DatabaseClient) {

    fun findDishesByCriteria(dishPageQueryDTO: DishPageQueryDTO):Mono<Result<PageResult<Dish>>>{
        var criteria = Criteria.empty()

        dishPageQueryDTO.name?.let {
            criteria = criteria.and("name").like("%$it%")
        }
        dishPageQueryDTO.categoryId?.let {
            criteria = criteria.and("category_id").`is`(it)
        }
        dishPageQueryDTO.status?.let {
            criteria = criteria.and("status").`is`(it)
        }
        val pageable = PageRequest.of(dishPageQueryDTO.page - 1, dishPageQueryDTO.pageSize)


        val query = Query.query(criteria).with(pageable)
        val countQuery = Query.query(criteria)

        return r2dbcEntityTemplate.select(query, Dish::class.java).collectList()
            .zipWith(r2dbcEntityTemplate.count(countQuery, Dish::class.java))
            .map { tuple -> PageImpl(tuple.t1, pageable, tuple.t2) }
            .map { page ->
                // 将Page<User>转换为你的PageResult<User>（假设你有一个类似的结构）
                Result.success(PageResult(total = page.totalElements, records = page.content))
            }
    }

    /**
     * 更新菜品
     */
    fun updateDish(dish: Dish): Mono<Long> {
        val updates = listOfNotNull(
            dish.description?.let { "description = :description" to it },
            dish.name?.let { "name = :name" to it },
            dish.price?.let { "price = :price" to it },
            dish.image?.let { "image = :image" to it },
            dish.categoryId?.let { "category_id = :categoryId" to it },
            dish.status?.let { "status = :status" to it },
            dish.updateTime?.let { "update_time = :updateTime" to it },
            dish.updateUser?.let { "update_user = :updateUser" to it }
        )

        if (updates.isEmpty() || dish.id == null) {
            return Mono.just(0L)
        }

        val setClause = updates.joinToString(", ") { it.first }
        val sql = "UPDATE dish SET $setClause WHERE id = :id"

        var updateSpec = databaseClient.sql(sql)
            .bind("id", dish.id!!)

        updates.forEach { (key, value) ->
            // Here we correct the split part to properly extract the named parameter from the SQL snippet
            val paramName = key.substringAfter(" = :")
            updateSpec = updateSpec.bind(paramName, value)
        }

        return updateSpec.fetch().rowsUpdated()
    }


    /**
     * 菜品统计
     */
    fun countByMap(status:Int?,categoryId:Long?): Mono<Int> {
        val sql = StringBuilder("select count(id) from dish where 1=1")


        status?.let{
            sql.append(" and status = :status")
        }
        categoryId?.let{
            sql.append(" and category_id = :categoryId")
        }


        var spec = databaseClient.sql(sql.toString())


        status?.let {
            spec = spec.bind("status", it)
        }
        categoryId?.let {
            spec = spec.bind("categoryId", it)
        }

        return spec.map { row -> row.get("count(id)", Int::class.java) }
            .one()
            .map { sum -> sum ?: 0 } // 如果 sum 为 null，则返回 0.0
            .onErrorResume {
                Mono.just(0) // 返回一个默认值，避免终止流程
            }
    }


}